﻿using IGS.Core.Systems;
using Moq;
using NUnit.Framework;

namespace IGS.Core.Tests.Systems
{
    public static class NBodySystemTests
    {
        [TestFixture]
        public class GivenNBodySystemWithTwoBodies
        {
            [Test]
            public void WhenLengthIsAccessedShouldReturnNumberOfBodiesContained()
            {
                // Arrange
                var bodies = new[]
                {
                    new Mock<IInteractable>().Object,
                    new Mock<IInteractable>().Object
                };
                var system = new NBodySystem(bodies);

                // Act
                var length = system.Length;

                // Assert
                Assert.AreEqual(2, length, "NBodySystem.Length");
            }

            [Test]
            public void WhenKineticEnergyIsAccessedShouldReturnSumOfAllBodyKineticEnergies()
            {
                // Arrange
                var body1 = new Mock<IInteractable>();
                body1.SetupGet(b => b.KineticEnergy).Returns(1.0);
                var body2 = new Mock<IInteractable>();
                body2.SetupGet(b => b.KineticEnergy).Returns(1.0);
                var bodies = new[]
                {
                    body1.Object,
                    body2.Object
                };
                var system = new NBodySystem(bodies);

                // Act
                var energy = system.KineticEnergy;

                // Assert
                body1.VerifyGet(b => b.KineticEnergy);
                body2.VerifyGet(b => b.KineticEnergy);
                Assert.AreEqual(2.0, energy, "NBodySystem.KineticEnergy");
            }

            [Test]
            public void WhenPotentialEnergyIsAccessedShouldReturnSumOfAllBodyPotentialEnergies()
            {
                // Arrange
                var body1 = new Mock<IInteractable>();
                body1.SetupGet(b => b.PotentialEnergy).Returns(-1.0);
                var body2 = new Mock<IInteractable>();
                body2.SetupGet(b => b.PotentialEnergy).Returns(-1.0);
                var bodies = new[]
                {
                    body1.Object,
                    body2.Object
                };
                var system = new NBodySystem(bodies);

                // Act
                var energy = system.PotentialEnergy;

                // Assert
                body1.VerifyGet(b => b.PotentialEnergy);
                body2.VerifyGet(b => b.PotentialEnergy);
                Assert.AreEqual(-1.0, energy, "NBodySystem.PotentialEnergy");
            }

            [Test]
            public void WhenNBodySystemIsIndexedShouldReturnSpecificBody()
            {
                // Arrange
                var bodies = new[]
                {
                    new Mock<IInteractable>().Object,
                    new Mock<IInteractable>().Object
                };
                var system = new NBodySystem(bodies);
                const int i = 0;

                // Act
                var body = system[i];

                // Assert
                Assert.AreEqual(bodies[i], body, "NBodySystem[i]");
            }
            
            [Test]
            public void WhenTheNBodySystemIsEnumeratedShouldReturnTheContainedBodies()
            {
                // Arrange
                var body1 = new Mock<IInteractable>();
                var body2 = new Mock<IInteractable>();
                var bodies = new[] {body1.Object, body2.Object};
                var system = new NBodySystem(bodies);

                // Act
                foreach (var body in system)
                {
                    // Assert
                    Assert.Contains(body, bodies, "NBodySystem.Enumerator.Current");
                }
            }
        }
    }
}
